package com.ucollege.threeabnradio;

import java.io.IOException;
import java.util.ArrayList;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;

public class RadioService extends Service {
	
	public static Boolean isRunning = false;
	private int state = MSG_Stopped;
	private MediaPlayer radio = null;
	private String radioUrl = "http://war.str3am.com:7180/live";
	private NotificationManager nm;
    
	ArrayList<Messenger> mClients = new ArrayList<Messenger>();
	int mValue = 0;  
	//possible messages
	static final int MSG_Register = 0;
	static final int MSG_Unregister = 1;
	static final int MSG_Playing = 2;
	static final int MSG_Buffering = 3;
	static final int MSG_Stopped = 4;
	static final int MSG_Play = 5;
	static final int MSG_Stop = 6;
	static final int MSG_Error = 7;
	
	final Messenger mMessenger = new Messenger(new IncomingHandler());
	
	@Override
	public IBinder onBind(Intent intent) {
		return mMessenger.getBinder();
	}
	
	class IncomingHandler extends Handler {
		@Override
		public void handleMessage (Message msg) {
			switch (msg.what) {
			case MSG_Register:
				mClients.add(msg.replyTo);
				sendState();
				break;
			case MSG_Unregister:
				mClients.remove(msg.replyTo);
				break;
			case MSG_Play:
				startStop();
				break;
			case MSG_Stop:
				
				break;
			default:
				super.handleMessage(msg);
			}
		}
	}
	
	private void sendMessage(int value) {
		for (int i=mClients.size()-1; i>=0; i--) {
			try {
				mClients.get(i).send(Message.obtain(null, value));
			} catch (RemoteException e) {
				mClients.remove(i);
			}
		}
	}
	
	private void sendState() {
		sendMessage(state);
	}
	
	//Listens for when the player is ready
	MediaPlayer.OnPreparedListener onPrepared = new MediaPlayer.OnPreparedListener() {
		public void onPrepared(MediaPlayer mp) {
			AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
			int result = audioManager.requestAudioFocus(onFocusChange, AudioManager.STREAM_MUSIC,
					AudioManager.AUDIOFOCUS_GAIN);
			if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
				stop();
			} else {
				updateNotification(getString(R.string.radioPlaying));
				radio.start();
				state = MSG_Playing;
				sendMessage(MSG_Playing);
			}
		}
	};
	//Will catch any errors with the asynchronous call
	MediaPlayer.OnErrorListener onError = new MediaPlayer.OnErrorListener() {
		public boolean onError(MediaPlayer mp, int what, int extra) {
			stop();
			return true;
		}
	};
	
	//Handle audio becoming noisy. Such as headphones being pulled out.
	android.content.BroadcastReceiver MusicIntentReceiver = new android.content.BroadcastReceiver() {
		   @Override
		   public void onReceive(Context ctx, Intent intent) {
		      if (intent.getAction().equals(android.media.AudioManager.ACTION_AUDIO_BECOMING_NOISY)) {
		          stop();
		      }
		   }
		};

	AudioManager.OnAudioFocusChangeListener onFocusChange = new AudioManager.OnAudioFocusChangeListener() {
		public void onAudioFocusChange(int focusChange) {
			switch (focusChange) {
		        case AudioManager.AUDIOFOCUS_GAIN:
		            // resume playback
		            if (radio == null) start();
		            else if (!radio.isPlaying()) radio.start();
		            radio.setVolume(1.0f, 1.0f);
		            break;
	
		        case AudioManager.AUDIOFOCUS_LOSS:
		            // Lost focus for an unbounded amount of time: stop playback and release media player
		            if (radio.isPlaying()) radio.stop();
		            radio.release();
		            radio = null;
		            break;
	
		        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
		            // Lost focus for a short time, but we have to stop
		            // playback. We don't release the media player because playback
		            // is likely to resume
		            if (radio.isPlaying()) radio.pause();
		            break;
	
		        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
		            // Lost focus for a short time, but it's ok to keep playing
		            // at an attenuated level
		            if (radio.isPlaying()) radio.setVolume(0.1f, 0.1f);
		            break;
			}	
		}
	};
	
	//constructor
	public RadioService() {
	}
	
	public static Boolean isRunning() {
		return isRunning;
	}
	
	private void showNotification() {
		nm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
		// In this sample, we'll use the same text for the ticker and the expanded notification
		CharSequence text = getString(R.string.radioStarted);
		// Set the icon, scrolling text and timestamp
		Notification notification = new Notification(R.drawable.notificationicon, text, System.currentTimeMillis());
		// The PendingIntent to launch our activity if the user selects this notification
		PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, threeabnradioActivity.class), 0);
		// Set the info for the views that show in the notification panel.
		notification.setLatestEventInfo(this, "3ABN Radio", text, contentIntent);
		// Send the notification.
		// We use a layout id because it is a unique number.  We use it later to cancel.
		//nm.notify(R.string.app_name, notification);
		startForeground(R.string.app_name, notification);
	}
	
	private void updateNotification(String notificationText) {
		nm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
		// In this sample, we'll use the same text for the ticker and the expanded notification
		CharSequence text = notificationText;
		// Set the icon, scrolling text and timestamp
		Notification notification = new Notification(R.drawable.notificationicon, text, System.currentTimeMillis());
		// The PendingIntent to launch our activity if the user selects this notification
		PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, threeabnradioActivity.class), 0);
		// Set the info for the views that show in the notification panel.
		notification.setLatestEventInfo(this, "3ABN Radio", text, contentIntent);
		// Send the notification.
		// We use a layout id because it is a unique number.  We use it later to cancel.
		nm.notify(R.string.app_name, notification);
	}
	
	public void startStop() {
		if (state == MSG_Stopped) {
			start();
		} else if (state == MSG_Playing){
			stop();
		} else {
			stop();
		}
	}
	
	//start the stream
	public void start() {
		radio = new MediaPlayer();
		radio.setAudioStreamType(AudioManager.STREAM_MUSIC);
		try {
			radio.setDataSource(radioUrl);
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalStateException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		radio.setOnPreparedListener(onPrepared);
		radio.setOnErrorListener(onError);
		radio.prepareAsync();
		state = MSG_Buffering;
		sendMessage(MSG_Buffering);
		showNotification();
		updateNotification(getString(R.string.radioBuffering));
	}
	
	//stops the playback, but the stream doesn't have to be prepared again to restart
	public void pause() {
		radio.pause();
	}
	
	//stops the stream
	public void stop() {
		stopForeground(true);
		nm.cancel(R.string.app_name);
		sendMessage(MSG_Stopped);
		state = MSG_Stopped;
		if (radio.isPlaying()) {
			radio.stop();
		}
		if (radio != null) {
			radio.release();
			radio = null;
		}
	}

	@Override
	public void onCreate() {
		isRunning = true;
		start();
	}
	
	@Override
	public void onDestroy() {
		if (radio != null) { 
			radio.release();
			radio = null;
		}
	}
}
